package com.wjk.kylin.mall.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.wjk.kylin.mall.admin.beanmapper.MenuEntityMapper;
import com.wjk.kylin.mall.admin.bo.MenuBO;
import com.wjk.kylin.mall.admin.dto.MetaDTO;
import com.wjk.kylin.mall.admin.dto.RouterDTO;
import com.wjk.kylin.mall.admin.entity.MenuEntity;
import com.wjk.kylin.mall.admin.entity.UserEntity;
import com.wjk.kylin.mall.admin.mapper.MenuMapper;
import com.wjk.kylin.mall.admin.service.IMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wjk.kylin.mall.common.core.constant.Constants;
import com.wjk.kylin.mall.common.core.dto.admin.UserIdInDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author wangjinkui
 * @since 2021-11-14
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements IMenuService {

    @Override
    public List<String> findMenuPermsByUserToUser(UserEntity user) {
        List<String> list = new ArrayList<>();
        // 管理员拥有所有权限 TODO
        if (1 == user.getId()) {
            list.add("*:*:*");
        } else {
            list = baseMapper.findMenuPermsByUserId(user.getId());
        }

        if (CollectionUtil.isNotEmpty(list)) {
            list = list.stream().filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        }

        return list;
    }

    @Override
    public List<RouterDTO> getRouters(Long userId) {
        List<MenuBO> menuList = findMenuTreeByUserId(userId);
        return buildMenus(menuList);
    }

    /**
     * 根据用户id查询权限
     *
     * @param inDTO
     * @return
     */
    @Override
    public List<String> getMenuPermsByUser(UserIdInDTO inDTO) {
        List<String> list = new ArrayList<>();
        //TODO 管理员拥有所有权限
        if (inDTO.getUserId() == 1) {
            list = baseMapper.findMenuPermsList();
        } else {
            list = baseMapper.findMenuPermsByUserId(inDTO.getUserId());
        }
        if (CollectionUtil.isNotEmpty(list)) {
            list = list.stream().filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        }
        return list;
    }

    /**
     * 菜单集合
     *
     * @param userId
     * @return
     */
    public List<MenuBO> findMenuTreeByUserId(Long userId) {
        List<MenuEntity> menuList = new ArrayList<>();
        if (1 == userId) {
            menuList = baseMapper.findMenu();
        } else {
            menuList = baseMapper.findMenuByUserId(userId);
        }
        List<MenuBO> menuBOList = MenuEntityMapper.INSTANCE.entity2BOs(menuList);
        return listWithTree(menuBOList, 0L);
    }

    /**
     * 组装成父子的树形结构
     *
     * @param menuList
     * @return
     */
    public List<MenuBO> listWithTree(List<MenuBO> menuList, Long id) {
        List<MenuBO> rootList = menuList.stream().filter(menu ->
                menu.getParentId().equals(id)
        ).map(menu -> {
            menu.setChildren(listWithTree(menuList, menu.getId()));
            return menu;
        }).sorted(Comparator.comparing(MenuBO::getSort))
                .collect(Collectors.toList());
        return rootList;
    }

    /**
     * 获取路由 根据菜单
     *
     * @param menuBOList
     * @return
     */
    public List<RouterDTO> buildMenus(List<MenuBO> menuBOList) {
        List<RouterDTO> routerList = new LinkedList<>();
        for (MenuBO menu : menuBOList) {
            RouterDTO router = new RouterDTO();

            router.setHidden(menu.getIsHidden());
            router.setName(getRouteName(menu));//首字母大写
            router.setPath(getRouterPath(menu));//获取路由地址
            router.setQuery(menu.getQuery());
            router.setComponent(getComponent(menu));
            router.setMeta(new MetaDTO(menu.getName(), menu.getIcon(), !menu.getIsCache(), menu.getPath()));

            List<MenuBO> childrenMenuBOList = menu.getChildren();
            if (CollectionUtil.isNotEmpty(childrenMenuBOList) && 1 == menu.getMenuType()) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(childrenMenuBOList));
            } else if (isMenuFrame(menu)) {
                router.setMeta(null);
                List<RouterDTO> childrenList = new ArrayList<>();

                RouterDTO children = new RouterDTO();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaDTO(menu.getName(), menu.getIcon(), !menu.getIsCache(), menu.getPath()));
                children.setQuery(menu.getQuery());
                childrenList.add(children);

                router.setChildren(childrenList);
            } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) {
                router.setMeta(new MetaDTO(menu.getName(), menu.getIcon()));
                router.setPath("/inner");
                List<RouterDTO> childrenList = new ArrayList<>();
                RouterDTO children = new RouterDTO();
                String routerPath = StringUtils.replaceEach(menu.getPath(), new String[]{Constants.HTTP, Constants.HTTPS}, new String[]{"", ""});
                children.setPath(routerPath);
                children.setComponent(Constants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaDTO(menu.getName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routerList.add(router);
        }
        return routerList;
    }

    /**
     * 获取组件信息
     *
     * @param menu 菜单信息
     * @return 组件信息
     */
    public String getComponent(MenuBO menu) {
        String component = Constants.LAYOUT;
        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) {
            component = menu.getComponent();
        } else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
            component = Constants.INNER_LINK;
        } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) {
            component = Constants.PARENT_VIEW;
        }
        return component;
    }

    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    public String getRouterPath(MenuBO menu) {
        String routerPath = menu.getPath();
        // 内链打开外网方式
        if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) {
            routerPath = StringUtils.replaceEach(routerPath, new String[]{Constants.HTTP, Constants.HTTPS}, new String[]{"", ""});
        }
        // 非外链并且是一级目录（类型为目录）
        if (0 == menu.getParentId().intValue() && 1 == menu.getMenuType() && !menu.getIsFrame()) {
            routerPath = "/" + menu.getPath();
        }
        // 非外链并且是一级目录（类型为菜单）
        else if (isMenuFrame(menu)) {
            routerPath = "/";
        }
        return routerPath;
    }

    /**
     * 获取路由名称
     *
     * @param menu 菜单信息
     * @return 路由名称
     */
    public String getRouteName(MenuBO menu) {
        String routerName = StringUtils.capitalize(menu.getPath());
        // 非外链并且是一级目录（类型为目录）
        if (isMenuFrame(menu)) {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isMenuFrame(MenuBO menu) {
        return menu.getParentId().intValue() == 0 && 2 == menu.getMenuType() && !menu.getIsFrame();
    }

    /**
     * 是否为parent_view组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isParentView(MenuBO menu) {
        return menu.getParentId().intValue() != 0 && 1 == menu.getMenuType();
    }

    /**
     * 是否为内链组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isInnerLink(MenuBO menu) {
        return !menu.getIsFrame() && isHttp(menu.getPath());
    }

    /**
     * 是否为http(s)://开头
     *
     * @param link 链接
     * @return 结果
     */
    public static boolean isHttp(String link) {
        return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
    }
}
